/**
 * 除了使用 typeof 以外，还可以使用许多类似的方式来进行 类型保护，
 * 只要它能够在 联合类型 的类型成员中起到筛选作用。
 * 
 * in 操作符 并不是 TypeScript 中新增的概念，
 * 而是 JavaScript 中已有的部分，它可以通过 key in object 的方式来判断 key 是否存在于 object 或其原型链上（返回 true 说明存在）。
 * 既然能起到区分作用，那么 TypeScript 中自然也可以用它来保护类型：
*/
/**
 * 在 接口 Foo 和 Bar 中，
 * foo / bar 和 fooOnly / barOnly 是各个类型独有的属性，
 * 因此可以作为 可辨识属性（Discriminant Property 或 Tagged Property）。
 * Foo 与 Bar 又因为存在这样具有区分能力的辨识属性，可以称为 可辨识联合类型（Discriminated Unions 或 Tagged Union）。
*/
interface Foo {
    foo: string;
    fooOnly: boolean;
    shared: number;
}
interface Bar {
    bar: string;
    barOnly: boolean;
    shared: number;
}
function handle(input: Foo | Bar) {
    if ('foo' in input) {
        input.fooOnly;
    } else {
        input.barOnly;
    }
}
//所以，在上面 接口 Foo 和 Bar 中，shared 不能用来区分，因为它同时存在两个类型中不具有辨识度
function handleA(input: Foo | Bar) {
    if ('shared' in input) {
        // 类型“Foo | Bar”上不存在属性“fooOnly”。类型“Bar”上不存在属性“fooOnly”。
        input.fooOnly;
    } else {
        // 类型“never”上不存在属性“barOnly”。
        input.barOnly;
    }
}
/**
 * 这个可辨识属性可以是结构层面的，比如结构 A 的属性 prop 是数组，而结构 B 的属性 prop 是对象，
 * 或者结构 A 中存在属性 prop 而结构 B 中不存在。
 * 甚至可以是 共同属性 的 字面量类型差异
*/
//可辨识属性是 结构层面 的
function ensureArray(input: number | number[]): number[] {
    if (Array.isArray(input)) {
        return input;
    } else {
        return [input];
    }
}
//共同属性 的 字面量类型差异
interface FooA {
    kind: 'foo';
    diffType: string;
    fooOnly: boolean;
    shared: number;
}

interface BarA {
    kind: 'bar';
    diffType: number;
    barOnly: boolean;
    shared: number;
}
function handleB(input: FooA | BarA) {
    if (input.kind === 'foo') {
        input.fooOnly;
    } else {
        input.barOnly;
    }
}
//对于同名但不同类型的属性，需要使用 字面量类型 的区分，并不能使用 typeof：
function handleC(input: FooA | BarA) {
    // 报错，并没有起到区分的作用，在两个代码块中都是 FooA | BarA
    if (typeof input.diffType === 'string') {
        input.fooOnly;
    } else {
        input.barOnly;
    }
}

//export {}：解决“无法重新声明块范围变量”错误提示问题
export { }